#!/usr/bin/env bash
set -e

# Outputs a label based on the size of the diff between the current branch and the main branch.

# env setting defaults
if [ -z "$MAIN_BRANCH" ]; then
    MAIN_BRANCH=master
fi
if [ -z "$FAIL_IF_XL" ]; then
    FAIL_IF_XL=0
fi

# const settings
IGNORE_PATTERN_FILE=.labelignore
XS_LABEL=size/xs
XS_MAX=20
S_LABEL=size/s
S_MAX=100
M_LABEL=size/m
M_MAX=250
L_LABEL=size/l
L_MAX=500
XL_LABEL=size/xl

if [ -z "$DEBUG" ]; then
    DEBUG=0
fi
if [ "$1" = "--debug" ]; then
    DEBUG=1
fi

# debug works like echo but only prints when --debug is passed and to stderr
debug() {
    if [ $DEBUG -eq 1 ]; then
        echo "$1" >&2
    fi
}

IGNORE_ARGS=()

# Get a list of files including the "generated by" header, then filter them out by only those with DO NOT EDIT on the first line, in case we have code in the repo that does the generation.
while IFS= read -r file; do
    # include only files where DO NOT EDIT appears on the very first line
    if head -n 1 "$file" | grep -q "DO NOT EDIT"; then
        debug "IGNORE: generated file: $file"
        IGNORE_ARGS+=(":(exclude)$file")
    fi
done < <(git grep -l -e 'generated by .* DO NOT EDIT')

# Read the .labelignore file and add the resolved files to the IGNORE_ARGS array.
while IFS= read -r pattern; do
    # Skip empty lines and comments
    case "$pattern" in
    '' | \#*) continue ;;
    esac

    # Use git ls-files with the pattern
    while IFS= read -r file; do
        debug "IGNORE: pattern '$pattern': $file"
        IGNORE_ARGS+=(":(exclude)$file")
    done < <(git ls-files "$pattern")
done < <(cat "$IGNORE_PATTERN_FILE" 2>/dev/null)

# Perform diff for merging to the main branch:
# --ignore-blank-lines: ignore changes that only involve blank lines
# --numstat: output only the number of changes (per file)
# -w: ignore whitespace
# --diff-filter=d: exclude deleted files
# --minimal: produce the smallest diff possible
# --merge-base: find the common ancestor of the current branch and the main branch
# $IGNORE_ARGS[@]: list of `:(exclude)file` patterns to ignore
OUTPUT=$(
    if [ "$DEBUG" = "1" ]; then set -x; fi
    git diff --ignore-blank-lines --numstat -w --diff-filter=d --minimal --merge-base "origin/$MAIN_BRANCH" -- "${IGNORE_ARGS[@]}"
)

debug
debug "DIFF FILE STATS"
debug "==============="
debug "$OUTPUT"
debug

sum=$(
    echo "$OUTPUT" | awk '{ total += $1 + $2 } END { print total }'
)

debug "TOTAL: $sum"

LABEL=""
if [ $sum -le $XS_MAX ]; then
    LABEL=$XS_LABEL
elif [ $sum -le $S_MAX ]; then
    LABEL=$S_LABEL
elif [ $sum -le $M_MAX ]; then
    LABEL=$M_LABEL
elif [ $sum -le $L_MAX ]; then
    LABEL=$L_LABEL
else
    LABEL=$XL_LABEL
fi

debug "LABEL: $LABEL"

if [ $FAIL_IF_XL -eq 1 ] && [ "$LABEL" = "$XL_LABEL" ]; then
    echo ""
    echo "ERROR: This PR exceeds the maximum size of $L_MAX lines."
    echo "Please make sure you are NOT addressing multiple issues with one PR."
    exit 1
fi

echo "$LABEL"
